package com.hnzq.cloud.freshuserassembly.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.hnzq.cloud.dto.*;
import com.hnzq.cloud.freshuserassembly.domain.FreResource;
import com.hnzq.cloud.freshuserassembly.service.IFreResourceService;
import com.hnzq.cloud.freshuserassembly.util.JWTHelper;
import com.hnzq.cloud.freshuserassembly.domain.FreUser;
import com.hnzq.cloud.freshuserassembly.exception.FreshException;
import com.hnzq.cloud.freshuserassembly.exception.UserAccountException;
import com.hnzq.cloud.freshuserassembly.mapper.FreUserMapper;
import com.hnzq.cloud.freshuserassembly.service.IFreUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hnzq.cloud.freshuserassembly.util.WoniuBeanUtils;
import com.hnzq.cloud.param.*;
import org.apache.commons.lang.time.DateUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 周皓月
 * @since 2022-02-03
 */
@Service
public class FreUserServiceImpl extends ServiceImpl<FreUserMapper, FreUser> implements IFreUserService {

    /**
     * Redisson
     */
    @Resource
    private RedissonClient redisson;

    @Resource
    private IFreResourceService resourceService;

    /**
     * 用户注册或者后台新增用户
     * @param registerParam
     * @return
     */
    @Override
    public RegisterDto register(RegisterParam registerParam){

        //根据账号名字查询重复账号
        FreUser accountName = getOne(new QueryWrapper<FreUser>()
                .eq("account_name", registerParam.getAccountName())
                .eq("is_delete",0));

        if (accountName != null){
            throw new UserAccountException("该账号已存在，请重新输入",1001);
        }

        //根据用户名字查询重复账号
        FreUser userName = getOne(new QueryWrapper<FreUser>()
                .eq("user_name", registerParam.getUserName())
                .eq("is_delete", 0));

        if (userName != null){
            throw new UserAccountException("该用户名已存在，请重新输入",1002);
        }

        //根据用户手机号查询重复账号
        FreUser userPhone = getOne(new QueryWrapper<FreUser>()
                .eq("user_phone", registerParam.getUserPhone())
                .eq("is_delete", 0));

        if (userPhone != null){
            throw new UserAccountException("该手机号已存在，请重新输入",1003);
        }

        //根据用户邮箱查询重复账号
        FreUser userEmail = getOne(new QueryWrapper<FreUser>()
                .eq("user_email", registerParam.getUserEmail())
                .eq("is_delete", 0));

        if (userEmail != null){
            throw new UserAccountException("该邮箱已存在，请重新输入",1004);
        }

        //执行注册新增
        boolean flag = saveOrUpdate(WoniuBeanUtils.copyObject(registerParam, FreUser.class));
        if (flag){
            return WoniuBeanUtils.copyObject(registerParam,RegisterDto.class);
        }else {
            throw new UserAccountException("注册失败",1005);
        }
    }

    /**
     * 后台分页条件查询用户列表
     * @param findUsersParam
     * @return
     */
    @Override
    public PageUsersDto findUsersByCondition(FindUsersParam findUsersParam) {
        QueryWrapper<FreUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0);

        //角色状态
        if (findUsersParam.getAccountStatus() != null && !findUsersParam.getAccountStatus().equals("")) {
            queryWrapper.eq("account_status",findUsersParam.getAccountStatus());
        }

        //大于等于开始时间
        if ( findUsersParam.getStartTime() != null && !findUsersParam.getStartTime().equals("")) {
            queryWrapper.ge("raw_add_time", findUsersParam.getStartTime());
        }

        //小于等于结束时间
        if (findUsersParam.getEndTime() != null && !findUsersParam.getEndTime().equals("")) {
            queryWrapper.le("raw_add_time", findUsersParam.getEndTime());
        }

        //关键字查询
        if (findUsersParam.getKeyWord() != null && !findUsersParam.getKeyWord().trim().equals("")) {
            queryWrapper.and(qw -> {
                qw.like("user_name", findUsersParam.getKeyWord())
                        .or().like("user_id", findUsersParam.getKeyWord())
                        .or().like("user_age", findUsersParam.getKeyWord())
                        .or().like("user_sex", findUsersParam.getKeyWord());
            });
        }

        //根据条件进行分页查询
        IPage<FreUser> iPage = page(new Page<>(findUsersParam.getIndexPage()
                , findUsersParam.getPageSize()),queryWrapper);

        PageUsersDto pageUserDto = new PageUsersDto();
        pageUserDto.setCurrent(iPage.getCurrent());
        pageUserDto.setTotal(iPage.getTotal());
        pageUserDto.setUserDtoList(WoniuBeanUtils.copyList(iPage.getRecords(), UserDto.class));

        return pageUserDto;
    }


    /**
     * 后台更新用户
     * @param updateUserParam
     * @return
     */
    @Override
    public UserDto updateUserById(UpdateUserParam updateUserParam) throws UserAccountException, JsonProcessingException {

        //获取锁对象
        RLock lock = redisson.getLock("updateUserById");

        //是否获取锁
        if (lock.tryLock()){
            //从redis查询对象
            RBucket<Object> bucket = redisson.getBucket("userId:" + updateUserParam.getUserId());

            if (!bucket.isExists()){
                //查询数据库
                FreUser userDB = getById(updateUserParam.getUserId());
                if (userDB == null){
                    lock.unlock();
                    throw new UserAccountException("用户不存在",1008);
                }
                //设置参数后再存redis
                if (updateUserParam.getAccountStatus() != null && !updateUserParam.getAccountStatus().equals("")){
                    userDB.setAccountStatus(updateUserParam.getAccountStatus());
                }
                if (updateUserParam.getRoleId() != null && !updateUserParam.getRoleId().equals("")){
                    userDB.setRoleId(updateUserParam.getRoleId());
                }
                if (updateUserParam.getUserAge() != null && !updateUserParam.getUserAge().equals("")){
                    userDB.setUserAge(updateUserParam.getUserAge());
                }
                if (updateUserParam.getUserEmail() != null && !updateUserParam.getUserEmail().equals("")){
                    userDB.setUserEmail(updateUserParam.getUserEmail());
                }
                if (updateUserParam.getUserFaceimg() != null && !updateUserParam.getUserFaceimg().equals("")){
                    userDB.setUserFaceimg(updateUserParam.getUserFaceimg());
                }
                if (updateUserParam.getUserName() != null && !updateUserParam.getUserName().equals("")){
                    userDB.setUserName(updateUserParam.getUserName());
                }
                if (updateUserParam.getUserPhone() != null && !updateUserParam.getUserPhone().equals("")){
                    userDB.setUserPhone(updateUserParam.getUserPhone());
                }
                if (updateUserParam.getUserSex() != null && !updateUserParam.getUserSex().equals("")){
                    userDB.setUserSex(updateUserParam.getUserSex());
                }
                System.out.println("数据库对象=========="+userDB);
                //把从数据库查的对象存放redis
                bucket.set(userDB,2, TimeUnit.HOURS);

                //执行更新操作
                saveOrUpdate(WoniuBeanUtils.copyObject(updateUserParam,FreUser.class));
                //操作完数据库后解锁
                lock.unlock();
                return WoniuBeanUtils.copyObject(updateUserParam,UserDto.class);
            }
            //执行更新操作
            saveOrUpdate(WoniuBeanUtils.copyObject(updateUserParam,FreUser.class));

            //设置参数后再存redis
            FreUser redisUser = (FreUser) bucket.get();

            if (updateUserParam.getAccountStatus() != null && !updateUserParam.getAccountStatus().equals("")){
                redisUser.setAccountStatus(updateUserParam.getAccountStatus());
            }
            if (updateUserParam.getRoleId() != null && !updateUserParam.getRoleId().equals("")){
                redisUser.setRoleId(updateUserParam.getRoleId());
            }
            if (updateUserParam.getUserAge() != null && !updateUserParam.getUserAge().equals("")){
                redisUser.setUserAge(updateUserParam.getUserAge());
            }
            if (updateUserParam.getUserEmail() != null && !updateUserParam.getUserEmail().equals("")){
                redisUser.setUserEmail(updateUserParam.getUserEmail());
            }
            if (updateUserParam.getUserFaceimg() != null && !updateUserParam.getUserFaceimg().equals("")){
                redisUser.setUserFaceimg(updateUserParam.getUserFaceimg());
            }
            if (updateUserParam.getUserName() != null && !updateUserParam.getUserName().equals("")){
                redisUser.setUserName(updateUserParam.getUserName());
            }
            if (updateUserParam.getUserPhone() != null && !updateUserParam.getUserPhone().equals("")){
                redisUser.setUserPhone(updateUserParam.getUserPhone());
            }
            if (updateUserParam.getUserSex() != null && !updateUserParam.getUserSex().equals("")){
                redisUser.setUserSex(updateUserParam.getUserSex());
            }
            System.out.println("redis对象=========="+redisUser);
            //把从数据库查的对象存放redis
            bucket.set(redisUser,2, TimeUnit.HOURS);

            //操作完数据库后解锁
            lock.unlock();
            return WoniuBeanUtils.copyObject(updateUserParam,UserDto.class);
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }
    }

    /**
     * 后台删除用户
     * @param deleteUserParam
     * @return
     */
    @Override
    public Boolean deleteUserById(DeleteUserParam deleteUserParam) throws UserAccountException, JsonProcessingException {

        //获取锁对象
        RLock lock = redisson.getLock("deleteUserById");

        //是否获取锁
        if (lock.tryLock()){
            //从redis查询对象
            RBucket<Object> bucket = redisson.getBucket("userId:" + deleteUserParam.getUserId());

            if (!bucket.isExists()){
                //查询数据库
                FreUser userDB = getById(deleteUserParam.getUserId());
                if (userDB == null){
                    lock.unlock();
                    throw new UserAccountException("用户不存在",1008);
                }

                if (deleteUserParam.getIsDelete() != null && !deleteUserParam.getIsDelete().equals("")){
                    userDB.setIsDelete(deleteUserParam.getIsDelete());
                }

                //把从数据库查的对象存放redis
                bucket.set(userDB,2, TimeUnit.HOURS);

                //执行删除
                boolean bool = saveOrUpdate(WoniuBeanUtils.copyObject(deleteUserParam, FreUser.class));
                //操作完数据库后解锁
                lock.unlock();
                return bool;
            }
            //执行删除
            boolean bool = saveOrUpdate(WoniuBeanUtils.copyObject(deleteUserParam, FreUser.class));

            //设置参数后再存redis
            FreUser redisUser = (FreUser) bucket.get();
            if (deleteUserParam.getIsDelete() != null && !deleteUserParam.getIsDelete().equals("")){
                redisUser.setIsDelete(deleteUserParam.getIsDelete());
            }
            //把从数据库查的对象存放redis
            bucket.set(redisUser,2, TimeUnit.HOURS);

            //操作完数据库后解锁
            lock.unlock();
            return bool;
        }else {
            throw new FreshException("服务器繁忙，请稍后再试",5005);
        }


    }

    /**
     * 后台增加用户积分
     * @param addUserScoreParam
     * @return
     */
    @Override
    public Boolean addUserScore(AddUserScoreParam addUserScoreParam) throws UserAccountException, JsonProcessingException {

        //从redis查询对象
        RBucket<Object> bucket = redisson.getBucket("userId:" + addUserScoreParam.getUserId());

        if (!bucket.isExists()){
            //查询数据库
            FreUser userDB = getOne(new QueryWrapper<FreUser>().eq("user_id", addUserScoreParam.getUserId())
                    .eq("is_delete", 0));
            if (userDB == null){
                throw new UserAccountException("用户不存在",1008);
            }
            //把从数据库查的对象存放redis
            bucket.set(userDB,2, TimeUnit.HOURS);

            //执行修改积分
            return saveOrUpdate(WoniuBeanUtils.copyObject(addUserScoreParam,FreUser.class));
        }
        //执行修改积分
        return saveOrUpdate(WoniuBeanUtils.copyObject(addUserScoreParam,FreUser.class));
    }

    /**
     * 后台计算用户等级
     * @param userLevelParam
     * @return
     */
    @Override
    public Boolean caculateUserLevel(UserLevelParam userLevelParam) throws UserAccountException, JsonProcessingException {

        //从redis查询对象
        RBucket<Object> bucket = redisson.getBucket("userId:" + userLevelParam.getUserId());

        if (!bucket.isExists()){
            //查询数据库
            FreUser userDB = getOne(new QueryWrapper<FreUser>().eq("user_id", userLevelParam.getUserId())
                    .eq("is_delete", 0));
            if (userDB == null){
                throw new UserAccountException("用户不存在",1008);
            }
            //把从数据库查的对象存放redis
            bucket.set(userDB,2, TimeUnit.HOURS);

            //执行修改等级
            return saveOrUpdate(WoniuBeanUtils.copyObject(userLevelParam,FreUser.class));
        }
        //执行修改等级
        return saveOrUpdate(WoniuBeanUtils.copyObject(userLevelParam,FreUser.class));
    }

    @Override
    public String login(String accountName, String accountPassword) {
        QueryWrapper<FreUser> wrapper = new QueryWrapper<>();
        wrapper.eq("account_name",accountName);
        FreUser freUser = getOne(wrapper);
        if (freUser==null) throw new UserAccountException("用户名不存在",404);
        String token=null;
        if (accountPassword.equals(freUser.getAccountPassword())){
            Date expireDate = DateUtils.addDays(new Date(), 1);
            HashMap<String, Object> map = new HashMap<>();
            map.put("login:user","redis:login:accountName:"+freUser.getAccountName());
            JWTHelper jwtHelper = new JWTHelper();
            token = jwtHelper.createJWT(expireDate, map);
            HashMap<String, Object> data = new HashMap<>();
            data.put("userId",freUser.getUserId());
            data.put("token",token);
            data.put("roleId",freUser.getRoleId());
            RBucket<Object> bucket = redisson.getBucket("redis:login:accountName:" + freUser.getAccountName());
//            if (!bucket.isExists()){
//                bucket.set(data);
//            }
            bucket.set(data,2,TimeUnit.HOURS);
            RBucket<Object> userRedis = redisson.getBucket("userId:"+freUser.getUserId());
            userRedis.set(freUser);
            RBucket<Object> resourceRedis = redisson.getBucket("roleId:" + freUser.getRoleId());

            List<FreResource> allPublicResources = resourceService.getAllPublicResources();
            List<FreResource> resources = resourceService.getAllResourcesByRoleId(freUser.getRoleId());

            resources.addAll(allPublicResources);
            List<String> uris = resources.stream().map(item -> item.getResourceUri()).collect(Collectors.toList());
            System.out.println(uris);
            resourceRedis.set(uris);

        }else {
            throw new UserAccountException("用户名密码错误",404);
        }
        UserDto userDto = WoniuBeanUtils.copyObject(freUser, UserDto.class);
        return token;
    }

    /**
     * 登出
     */
    @Override
    public void loginOut() {
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        String userId = request.getHeader("userId");
        RBucket<Object> userRedis = redisson.getBucket("userId:" + userId);
        FreUser user = (FreUser) userRedis.get();
//        FreUser user = WoniuBeanUtils.copyObject(userRedis, FreUser.class);
        System.out.println(user);
        RBucket<Object> bucket = redisson.getBucket("redis:login:accountName:" + user.getAccountName());
        bucket.delete();
    }
}
